cmake_minimum_required(VERSION 3.20)
project(cpp_module_example)

# 设置 C++20 标准
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 检查编译器和版本
message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")

# 创建传统的可工作示例
add_executable(traditional_demo 
    traditional_example.cpp 
    comparison_main.cpp
)

# 创建模块概念示例
add_executable(working_demo 
    working_module.cpp
)

# 设置基本编译选项
target_compile_features(traditional_demo PUBLIC cxx_std_20)
target_compile_features(working_demo PUBLIC cxx_std_20)

# 添加编译器特定标志
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    target_compile_options(traditional_demo PRIVATE -Wall -Wextra -Wpedantic)
    target_compile_options(working_demo PRIVATE -Wall -Wextra -Wpedantic)
    
    # 检查 GCC 版本是否支持模块
    if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0")
        message(STATUS "GCC ${CMAKE_CXX_COMPILER_VERSION} detected - attempting module support...")
        
        # GCC 模块支持的实验性实现
        # 注意：GCC 的模块支持仍在开发中，可能需要特殊处理
        
        # 尝试使用 GCC 的模块标志
        set(GCC_MODULE_FLAGS "-fmodules-ts")
        
        # 创建使用 GCC 模块语法的简化示例
        add_executable(gcc_module_demo_simple)
        
        # 先尝试编译一个简单的模块文件
        set(SIMPLE_MODULE_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/simple_gcc_module.cpp")
        file(WRITE ${SIMPLE_MODULE_SOURCE} "
// 简化的 GCC 模块示例
#include <iostream>
#include <string>

// 模拟模块功能的命名空间
namespace GccModuleDemo {
    void greet(const std::string& name) {
        std::cout << \"Hello, \" << name << \" from GCC C++20!\" << std::endl;
    }
    
    class SimpleCalculator {
    private:
        std::string name;
    public:
        SimpleCalculator(const std::string& calc_name) : name(calc_name) {}
        
        int add(int a, int b) {
            std::cout << name << \": \" << a << \" + \" << b << \" = \";
            int result = a + b;
            std::cout << result << std::endl;
            return result;
        }
        
        int multiply(int a, int b) {
            std::cout << name << \": \" << a << \" * \" << b << \" = \";
            int result = a * b;
            std::cout << result << std::endl;
            return result;
        }
    };
    
    constexpr double PI = 3.14159265359;
    
    template<typename T>
    T max_value(T a, T b) {
        return (a > b) ? a : b;
    }
}

int main() {
    std::cout << \"=== GCC C++20 示例 ===\" << std::endl;
    
    GccModuleDemo::greet(\"GCC 用户\");
    
    GccModuleDemo::SimpleCalculator calc(\"GCC计算器\");
    calc.add(15, 25);
    calc.multiply(6, 7);
    
    std::cout << \"PI = \" << GccModuleDemo::PI << std::endl;
    
    auto max_int = GccModuleDemo::max_value(100, 200);
    auto max_double = GccModuleDemo::max_value(3.14, 2.71);
    std::cout << \"max(100, 200) = \" << max_int << std::endl;
    std::cout << \"max(3.14, 2.71) = \" << max_double << std::endl;
    
    return 0;
}
")
        
        target_sources(gcc_module_demo_simple PRIVATE ${SIMPLE_MODULE_SOURCE})
        target_compile_features(gcc_module_demo_simple PUBLIC cxx_std_20)
        target_compile_options(gcc_module_demo_simple PRIVATE -Wall -Wextra)
        
        # 尝试真正的 GCC 模块编译（实验性）
        if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28")
            message(STATUS "Attempting experimental GCC module support...")
            
            # 检查是否可以尝试模块编译
            try_compile(GCC_MODULE_TEST
                ${CMAKE_BINARY_DIR}/gcc_module_test
                SOURCES ${CMAKE_SOURCE_DIR}/math_operations.cppm
                CMAKE_FLAGS "-DCMAKE_CXX_STANDARD=20" "-DCMAKE_CXX_FLAGS=${GCC_MODULE_FLAGS}"
                OUTPUT_VARIABLE GCC_MODULE_OUTPUT
            )
            
            if(GCC_MODULE_TEST)
                message(STATUS "GCC module compilation test passed!")
                
                # 启用实验性模块支持
                set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "aa1f7df0-828a-4fcd-9afc-2dc80491aca7")
                set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
                
                # 尝试创建模块目标
                add_library(gcc_math_operations)
                target_sources(gcc_math_operations
                    PUBLIC
                        FILE_SET CXX_MODULES FILES
                        math_operations.cppm
                    PRIVATE
                        math_operations.cpp
                )
                target_compile_features(gcc_math_operations PUBLIC cxx_std_20)
                target_compile_options(gcc_math_operations PRIVATE ${GCC_MODULE_FLAGS})
                
                add_library(gcc_string_utils)
                target_sources(gcc_string_utils
                    PUBLIC
                        FILE_SET CXX_MODULES FILES
                        string_utils.cppm
                    PRIVATE
                        string_utils.cpp
                )
                target_compile_features(gcc_string_utils PUBLIC cxx_std_20)
                target_compile_options(gcc_string_utils PRIVATE ${GCC_MODULE_FLAGS})
                
                add_executable(gcc_real_module_demo main.cpp)
                target_link_libraries(gcc_real_module_demo PRIVATE gcc_math_operations gcc_string_utils)
                target_compile_features(gcc_real_module_demo PUBLIC cxx_std_20)
                target_compile_options(gcc_real_module_demo PRIVATE ${GCC_MODULE_FLAGS})
                
                message(STATUS "GCC module targets created!")
                
            else()
                message(WARNING "GCC module compilation test failed.")
                message(STATUS "Test output: ${GCC_MODULE_OUTPUT}")
                message(STATUS "Falling back to namespace-based approach.")
            endif()
        else()
            message(WARNING "CMake version ${CMAKE_VERSION} may not support experimental module features.")
        endif()
        
    else()
        message(WARNING "GCC version ${CMAKE_CXX_COMPILER_VERSION} may not fully support C++20 modules. GCC 11+ recommended.")
    endif()
    
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    target_compile_options(traditional_demo PRIVATE -Wall -Wextra)
    target_compile_options(working_demo PRIVATE -Wall -Wextra)
    
    if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.0")
        message(STATUS "Clang ${CMAKE_CXX_COMPILER_VERSION} detected - checking for clang-scan-deps...")
        
        find_program(CLANG_SCAN_DEPS clang-scan-deps)
        if(CLANG_SCAN_DEPS)
            message(STATUS "Found clang-scan-deps: ${CLANG_SCAN_DEPS}")
            message(STATUS "Clang module support available.")
            
            # 创建 Clang 特定的示例
            add_executable(clang_modern_demo clang_modern_demo.cpp)
            target_compile_features(clang_modern_demo PUBLIC cxx_std_20)
            target_compile_options(clang_modern_demo PRIVATE -Wall -Wextra -stdlib=libc++)
            target_link_options(clang_modern_demo PRIVATE -stdlib=libc++)
            
        else()
            message(WARNING "clang-scan-deps not found. Install with: sudo apt install clang-tools-18")
        endif()
    endif()
    
else()
    message(STATUS "Using default compiler settings for ${CMAKE_CXX_COMPILER_ID}")
endif()

# 创建运行目标
add_custom_target(run_traditional
    COMMAND traditional_demo
    DEPENDS traditional_demo
    COMMENT "Running traditional C++ example"
)

add_custom_target(run_working
    COMMAND working_demo
    DEPENDS working_demo
    COMMENT "Running module concept example"
)

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0")
    add_custom_target(run_gcc_simple
        COMMAND gcc_module_demo_simple
        DEPENDS gcc_module_demo_simple
        COMMENT "Running GCC simple module demo"
    )
    
    if(TARGET gcc_real_module_demo)
        add_custom_target(run_gcc_modules
            COMMAND gcc_real_module_demo
            DEPENDS gcc_real_module_demo
            COMMENT "Running GCC real modules demo"
        )
    endif()
endif()

if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.0")
    if(TARGET clang_modern_demo)
        add_custom_target(run_clang_modern
            COMMAND clang_modern_demo
            DEPENDS clang_modern_demo
            COMMENT "Running Clang modern C++20 demo"
        )
    endif()
endif()

# 显示构建信息
message(STATUS "")
message(STATUS "=== Build Configuration Summary ===")
message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
message(STATUS "C++ Standard: C++${CMAKE_CXX_STANDARD}")
message(STATUS "")
message(STATUS "Available targets:")
message(STATUS "  traditional_demo     - Traditional C++ with headers")
message(STATUS "  working_demo         - Module concept demonstration")

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0")
    message(STATUS "  gcc_module_demo_simple - GCC C++20 example")
    if(TARGET gcc_real_module_demo)
        message(STATUS "  gcc_real_module_demo   - GCC experimental modules")
    endif()
endif()

if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.0")
    if(TARGET clang_modern_demo)
        message(STATUS "  clang_modern_demo      - Clang C++20 modern features")
    endif()
endif()

message(STATUS "")
message(STATUS "Run targets:")
message(STATUS "  make run_traditional")
message(STATUS "  make run_working")

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0")
    message(STATUS "  make run_gcc_simple")
    if(TARGET gcc_real_module_demo)
        message(STATUS "  make run_gcc_modules")
    endif()
endif()

if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.0")
    if(TARGET clang_modern_demo)
        message(STATUS "  make run_clang_modern")
    endif()
endif()

message(STATUS "")
message(STATUS "To build with GCC: cmake ..")
message(STATUS "To build with Clang: CC=clang CXX=clang++ cmake ..")
message(STATUS "======================================")
